package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.cache.GmallCache;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.common.mqconstant.MqConst;
import com.atguigu.gmall.product.service.ManagerService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author wk
 * @create 2021-08-24 19:15
 */
@Service
public class ManagerServiceImpl implements ManagerService {
    @Autowired
    private BaseCategory1Mapper baseCategory1Mapper;
    @Autowired
    private BaseCategory2Mapper baseCategory2Mapper;
    @Autowired
    private BaseCategory3Mapper baseCategory3Mapper;
    @Autowired
    private BaseAttrInfoMapper baseAttrInfoMapper;
    @Autowired
    private BaseAttrValueMapper baseAttrValueMapper;
    @Autowired
    private BaseTrademarkMapper baseTrademarkMapper;
    @Autowired
    private SpuInfoMapper spuInfoMapper;
    @Autowired
    private BaseSaleAttrMapper baseSaleAttrMapper;
    @Autowired
    private SpuImageMapper spuImageMapper;
    @Autowired
    private SpuSaleAttrMapper spuSaleAttrMapper;
    @Autowired
    private SpuSaleAttrValueMapper spuSaleAttrValueMapper;
    @Autowired
    private SkuInfoMapper skuInfoMapper;
    @Autowired
    private SkuImageMapper skuImageMapper;
    @Autowired
    private SkuAttrValueMapper skuAttrValueMapper;
    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Autowired
    private BaseCategoryViewMapper baseCategoryViewMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RabbitService rabbitService;

    @Override
    public List<BaseCategory1> getCategory1() {
        return baseCategory1Mapper.selectList(null);
    }


    @Override
    public List<BaseCategory2> getCategory2(Long category1Id) {
        return baseCategory2Mapper.selectList(new QueryWrapper<BaseCategory2>().eq("category1_id", category1Id));
    }


    @Override
    public List<BaseCategory3> getCategory3(Long category2Id) {
        return baseCategory3Mapper.selectList(new QueryWrapper<BaseCategory3>().eq("category2_id", category2Id));
    }

    @Override
    public List<BaseAttrInfo> attrInfoList(Long category1Id, Long category2Id, Long category3Id) {
        return baseAttrInfoMapper.attrInfoList(category1Id, category2Id, category3Id);
    }

    //  保存平台属性及属性值 嵌套数据
    @Override
    public void saveAttrInfo(BaseAttrInfo baseAttrInfo) {
        // 往baseAttrInfo表中添加数据
        baseAttrInfoMapper.insert(baseAttrInfo);
        List<BaseAttrValue> attrValueList = baseAttrInfo.getAttrValueList();
        // 往BaseAttrValue表中添加值
        // 保存平台属性值
        for (BaseAttrValue attrValue : attrValueList) {
            // 设置外键
            attrValue.setAttrId(baseAttrInfo.getId());
            baseAttrValueMapper.insert(attrValue);
        }

    }

    @Override
    public List<BaseAttrValue> getAttrValueList(Long attrId) {

        List<BaseAttrValue> baseAttrValueList = baseAttrValueMapper.selectList(new QueryWrapper<BaseAttrValue>().eq("attr_id", attrId));
        return baseAttrValueList;
    }

    @Override
    public void updateAttrInfo(BaseAttrInfo baseAttrInfo) {
        List<BaseAttrValue> attrValueList = baseAttrInfo.getAttrValueList();
        for (BaseAttrValue attrValue : attrValueList) {
            // 设置外键
            attrValue.setAttrId(baseAttrInfo.getId());
            baseAttrValueMapper.updateById(attrValue);
        }
    }

    @Override
    public IPage baseTrademark(Integer page, Integer limit) {
        return baseTrademarkMapper.selectPage(new Page(page, limit), null);
    }

    @Override
    public void save(BaseTrademark baseTrademark) {
        baseTrademarkMapper.insert(baseTrademark);
    }

    @Override
    public BaseTrademark get(Long id) {
        return baseTrademarkMapper.selectById(id);
    }

    @Override
    public void update(BaseTrademark baseTrademark) {
        baseTrademarkMapper.update(baseTrademark, new QueryWrapper<BaseTrademark>().eq("id", baseTrademark.getId()));
    }

    @Override
    public void remove(Long id) {
        baseTrademarkMapper.delete(new QueryWrapper<BaseTrademark>().eq("id", id));
    }

    // 根据三级id查询spu列表
    @Override
    public IPage getSpuPage(Integer page, Integer limit, Long category3Id) {
        return spuInfoMapper.selectPage(new Page<>(page, limit), new QueryWrapper<SpuInfo>().eq("category3_id", category3Id));
    }

    @Override
    public List<BaseTrademark> getTrademarkList() {
        return baseTrademarkMapper.selectList(null);
    }

    @Override
    public List<BaseSaleAttr> getSaleAttrList() {
        return baseSaleAttrMapper.selectList(null);
    }

    @Override
    public void saveSpuInfo(SpuInfo spuInfo) {
        // 1.往商品表中添加数据
        spuInfoMapper.insert(spuInfo);
        // 2.往商品图片表中添加数据
        List<SpuImage> spuImageList = spuInfo.getSpuImageList();
        spuImageList.forEach(spuImage -> {
            // 设置外键
            spuImage.setSpuId(spuInfo.getId());
            spuImageMapper.insert(spuImage);
        });
        // 3.往销售属性表中添加数据
        List<SpuSaleAttr> spuSaleAttrList = spuInfo.getSpuSaleAttrList();
        spuSaleAttrList.forEach(spuSaleAttr -> {
            // 设置外键
            spuSaleAttr.setSpuId(spuInfo.getId());
            spuSaleAttrMapper.insert(spuSaleAttr);
            // 4.往销售表属性值表中添加数据
            List<SpuSaleAttrValue> spuSaleAttrValueList = spuSaleAttr.getSpuSaleAttrValueList();
            spuSaleAttrValueList.forEach(spuSaleAttrValue -> {
                // 设置外键
                spuSaleAttrValue.setSpuId(spuInfo.getId());
                // 设置销售属性名称
                spuSaleAttrValue.setSaleAttrName(spuSaleAttr.getSaleAttrName());
                spuSaleAttrValueMapper.insert(spuSaleAttrValue);
            });
        });

    }

    @Override
    public IPage<SkuInfo> skuPageList(Integer page, Integer limit) {
        return skuInfoMapper.selectPage(new Page<>(page, limit), null);
    }

    @Override
    public List<SpuImage> getSpuImageList(Long spuId) {
        return spuImageMapper.selectList(new QueryWrapper<SpuImage>().eq("spu_id", spuId));
    }

    /**
     * 根据spuId获取销售属性机属性值集合
     *
     * @param spuId
     * @return
     */
    @Override
    public List<SpuSaleAttr> getSpuSaleAttrList(Long spuId) {
        return spuSaleAttrMapper.selectSpuSaleAttrList(spuId);
    }

    @Override
    public void saveSkuInfo(SkuInfo skuInfo) {
        // 1.往sku_info表中添加数据
        skuInfoMapper.insert(skuInfo);
        // 2.往sku_image表中添加数据
        List<SkuImage> skuImageList = skuInfo.getSkuImageList();
        skuImageList.forEach(skuImage -> {
            // 设置外键skuId
            skuImage.setSkuId(skuInfo.getId());
            skuImageMapper.insert(skuImage);
        });
        // 3.往sku_sale_attr表中添加数据
        List<SkuAttrValue> skuAttrValueList = skuInfo.getSkuAttrValueList();
        skuAttrValueList.forEach(skuAttrValue -> {
            // 设置外键skuId
            skuAttrValue.setSkuId(skuInfo.getId());
            skuAttrValueMapper.insert(skuAttrValue);
        });
        // 4.往sku_sale_attr_value表中添加数据
        List<SkuSaleAttrValue> skuSaleAttrValueList = skuInfo.getSkuSaleAttrValueList();
        skuSaleAttrValueList.forEach(skuSaleAttrValue -> {
            // 设置外键skuId
            skuSaleAttrValue.setSkuId(skuInfo.getId());
            // 设置外键SpuId
            skuSaleAttrValue.setSpuId(skuInfo.getSpuId());
            skuSaleAttrValueMapper.insert(skuSaleAttrValue);
        });
    }

    // 上架
    @Override
    public void onSave(Long skuId) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(skuId);
        skuInfo.setIsSale(SkuInfo.IS_SALE);
        skuInfoMapper.updateById(skuInfo);
        // 发消息通知ES索引库 添加索引
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_GOODS,
                MqConst.ROUTING_GOODS_UPPER, skuId);

    }

    // 下架
    @Override
    public void cancelSale(Long skuId) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(skuId);
        skuInfo.setIsSale(SkuInfo.NO_SALE);
        skuInfoMapper.updateById(skuInfo);
        // 发消息通知ES索引库 删除索引
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_GOODS,
                MqConst.ROUTING_GOODS_LOWER, skuId);
    }
    /**
     * 根据库存id查询库存信息和图片
     * 库存信息中包含图片列表
     *
     * @param skuId
     * @return
     */
    @Override
    @GmallCache(prefix = RedisConst.SKUKEY_PREFIX)
    public SkuInfo getSkuInfo(Long skuId) {
        // 查询库存信息
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        // 查询图片
        List<SkuImage> skuImageList = skuImageMapper.selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
        skuInfo.setSkuImageList(skuImageList);
        return skuInfo;
    }
   /* @Override
    public SkuInfo getSkuInfo(Long skuId) {
        // 优化查询
        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
        // 1.应该先查询redis
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
        // 2.如果存在则直接返回
        if (skuInfo == null) {
            // 缓存三大问题之缓存击穿 一个热点键
            // 使用分布式锁 加锁(使用过期不候锁) 当有数据拿到锁后 其余数据等待之后去缓存中获取数据
            // 2.1设置锁的key
            String cacheClock = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKULOCK_SUFFIX;
            // 2.2 设置uuid作为锁名 可以避免误删操作
            String uuid = UUID.randomUUID().toString();
            // 2.3为彻底防止死锁设置过期时间
             Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(cacheClock, uuid, 2, TimeUnit.SECONDS);
            // 获取到了锁
            if (ifAbsent) {
                try {
                    // 3.如果缓存中没有再去查数据库
                    skuInfo = skuInfoMapper.selectById(skuId);
                    if (skuInfo != null) {
                        // 4.设置图片
                        List<SkuImage> skuImageList = skuImageMapper.selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
                        skuInfo.setSkuImageList(skuImageList);
                        // 保存到redis中
                        // 避免 缓存雪崩 通过添加随机数设置不同的过期时间
                        redisTemplate.opsForValue().set(cacheKey, skuInfo, RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(300), TimeUnit.SECONDS);
                    } else {
                        // 为避免缓存穿透 将null值存储在缓存中并设置过期时间 从而减轻数据库的压力
                        skuInfo = new SkuInfo();// 结果为空
                        redisTemplate.opsForValue().set(cacheKey, skuInfo, 5, TimeUnit.MINUTES);
                    }
                } finally {
                    // 避免死锁 务必要解锁将其添加在finally中 使用LUA脚本
                    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
                    this.redisTemplate.execute(new DefaultRedisScript<>(script), Collections.singletonList(cacheClock), uuid);
                }
            } else {
                // 未获取到锁
                try {
                    // 睡一会 等待获取到锁的的操作将数据保存到缓存中
                    TimeUnit.SECONDS.sleep(5);
                    // 然后再从缓存中获取数据
                    skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        // 5.返回数据
        return skuInfo;
    }*/
    /*@Override
    public SkuInfo getSkuInfo(Long skuId) {
        // 优化查询
        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
        // 1.应该先查询redis
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
        // 2.如果存在则直接返回
        if (skuInfo == null) {
            // 缓存三大问题之缓存击穿 一个热点键
            // 使用分布式锁 加锁(使用过期不候锁) 当有数据拿到锁后 其余数据等待之后去缓存中获取数据
            // 2.1设置锁的key
            String cacheClock = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKULOCK_SUFFIX;
            // 2.2 设置uuid作为锁名 可以避免误删操作
            //String uuid = UUID.randomUUID().toString();
            // 2.3为彻底防止死锁设置过期时间
             //Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(cacheClock, uuid, 2, TimeUnit.SECONDS);
            // 使用redisson框架简化redis设置分布式锁
            RLock lock = redissonClient.getLock(cacheClock);
            //boolean ifAbsent = lock.tryLock(1, 2, TimeUnit.SECONDS);
            boolean ifAbsent = false;
            try {
                // 参数1：获取锁的时间
                // 参数2：锁的过期时间
                // 参数3：单位
                // 上锁
                ifAbsent = lock.tryLock(1, 3, TimeUnit.SECONDS);
                // 获取到了锁
                if (ifAbsent) {
                    try {
                        // 3.如果缓存中没有再去查数据库
                        skuInfo = skuInfoMapper.selectById(skuId);
                        if (skuInfo != null) {
                            // 4.设置图片
                            List<SkuImage> skuImageList = skuImageMapper.selectList(new QueryWrapper<SkuImage>().eq("sku_id", skuId));
                            skuInfo.setSkuImageList(skuImageList);
                            // 保存到redis中
                            // 避免 缓存雪崩 通过添加随机数设置不同的过期时间
                            redisTemplate.opsForValue().set(cacheKey, skuInfo, RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(300), TimeUnit.SECONDS);
                        } else {
                            // 为避免缓存穿透 将null值存储在缓存中并设置过期时间 从而减轻数据库的压力
                            skuInfo = new SkuInfo();// 结果为空
                            redisTemplate.opsForValue().set(cacheKey, skuInfo, 5, TimeUnit.MINUTES);
                        }
                    } finally {
                        // 避免死锁 务必要解锁将其添加在finally中 使用LUA脚本
                        lock.unlock();
                    }
                } else {
                    // 未获取到锁
                    try {
                        // 睡一会 等待获取到锁的的操作将数据保存到缓存中
                        TimeUnit.SECONDS.sleep(5);
                        // 然后再从缓存中获取数据
                        skuInfo = (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 5.返回数据
        return skuInfo;
    }*/

    /**
     * @param category3Id 三级标题id
     * @return 一二三级分类视图
     * 三表联查,因为查询的次数会很多，
     * 所以可以将其封装为视图  可以将入参作为视图的id
     * 每次查询调用视图进行查询效率会高(不会再进行语法之类的检查校验)
     */
   /* @Override
    public BaseCategoryView getBaseCategoryView(Long category3Id) {
        return baseCategoryViewMapper.selectById(category3Id);
    }*/
    @Override
    public BaseCategoryView getBaseCategoryView(Long category3Id) {
        // 优化添加缓存
        String redisKey = RedisConst.CATEGORYVIEW_PREFIX + category3Id + RedisConst.CATEGORYVIEW_SUFFIX;
        // 1.先查询缓存
        BaseCategoryView baseCategoryView = (BaseCategoryView) redisTemplate.opsForValue().get(redisKey);
        // 2.如果有则直接返回
        if (baseCategoryView == null) {
            // 2.1为避免缓存击穿问题使用分布式锁
            // 设置分布式锁key
            String cacheClock = RedisConst.CATEGORYVIEW_PREFIX + category3Id + RedisConst.SKULOCK_SUFFIX;
            // 设置分布式锁名 解决 分布式锁问题之误删操作
            String uuid = UUID.randomUUID().toString();
            // 设置锁 并设置过期时间+最后释放锁 解决 分布式锁问题之死锁问题
            Boolean lockIsAbsent = redisTemplate.opsForValue().setIfAbsent(cacheClock, uuid, 2, TimeUnit.SECONDS);
            // 判断是否有锁
            if (lockIsAbsent) {
                try {
                    // 3.如果缓存中没有 则从数据库中查询
                    baseCategoryView = baseCategoryViewMapper.selectById(category3Id);
                    if (baseCategoryView != null) {
                        // 4.存入缓存并返回数据
                        // 避免 缓存雪崩 设置不同的过期时间
                        redisTemplate.opsForValue().
                                set(redisKey, baseCategoryView, RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(500), TimeUnit.SECONDS);
                    } else {
                        // 如果数据库和缓存中都没有此数据 避免缓存穿透
                        // 将查询到的null值存入缓存中
                        baseCategoryView = new BaseCategoryView();
                        redisTemplate.opsForValue().set(redisKey, baseCategoryView, 5, TimeUnit.MINUTES);
                    }
                } finally {
                    // 避免死锁 务必要解锁将其添加在finally中 使用LUA脚本
                    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
                    this.redisTemplate.execute(new DefaultRedisScript<>(script), Collections.singletonList(cacheClock), uuid);
                }
            } else {
                // 未获取到锁
                try {
                    // 等待 获取到锁的服务将数据保存到缓存中
                    TimeUnit.SECONDS.sleep(5);
                    // 再次查询缓存
                    baseCategoryView = (BaseCategoryView) redisTemplate.opsForValue().get(redisKey);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        // 返回数据
        return baseCategoryView;
    }

    /**
     * 根据库存id获取价格信息
     *
     * @param skuId
     * @return 价格不可以缓存 必须显示实时数据
     */
    @Override
    public BigDecimal getSkuPrice(Long skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        // 对查询结果进行判断
        if (skuInfo != null) {
            return skuInfo.getPrice();
        }
        return new BigDecimal(0);
    }

    /**
     * 根据spuId，skuId 查询销售属性及值集合 （选中项）标红
     *
     * @param skuId
     * @param spuId
     * @return
     */
    /*@Override
    public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) {
        return spuSaleAttrMapper.getSpuSaleAttrListCheckBySku(skuId, spuId);
    }*/
    @Override
    public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) {
        // 优化添加缓存
        // 1.先查询缓存
        String redisKey = RedisConst.SPUSALEATTR_PREFIX + skuId + spuId + RedisConst.SPUSALEATTR_SUFFIX;
        List<SpuSaleAttr> spuSaleAttrListCheckBySku = (List<SpuSaleAttr>) redisTemplate.opsForValue().get(redisKey);
        // 2.如果有则直接返回
        if (spuSaleAttrListCheckBySku == null) {
            // 2.1解决缓存问题之缓存击穿 使用分布式锁
            // 2.2设置分布式锁key
            String cacheClock = RedisConst.SPUSALEATTR_PREFIX + skuId + spuId + RedisConst.SKULOCK_SUFFIX;
            // 2.3 设置分布式锁名 解决 分布式锁问题之误删操作
            // String uuid = UUID.randomUUID().toString();
            // 2.4 设置过期时间+最后的解锁操作 解决 分布式锁问题之死锁
            // Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(cacheClock, uuid, 3, TimeUnit.SECONDS);
            // 使用redisson框架封装简化分布式锁
            RLock lock = redissonClient.getLock(cacheClock);
            boolean ifAbsent = false;
            try {
                ifAbsent = lock.tryLock(1, 3, TimeUnit.SECONDS);// 使用过期不候锁
                // 2.5是否得到锁
                if (ifAbsent) {
                    try {
                        // 3.如果没有 则从数据库中查询
                        spuSaleAttrListCheckBySku = spuSaleAttrMapper.getSpuSaleAttrListCheckBySku(skuId, spuId);
                        if (spuSaleAttrListCheckBySku != null) {
                            // 4.存入缓存并返回数据
                            // 避免缓存雪崩 设置不同的过期时间
                            redisTemplate.opsForValue().set(redisKey, spuSaleAttrListCheckBySku, RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(500), TimeUnit.SECONDS);
                        } else {
                            // 如果数据库和缓存中都没有此数据 避免缓存穿透
                            // 将查询到的null值存入缓存中
                            spuSaleAttrListCheckBySku = new ArrayList<SpuSaleAttr>();
                            redisTemplate.opsForValue().set(redisKey, spuSaleAttrListCheckBySku, 5, TimeUnit.MINUTES);
                        }
                    } finally {
                        // 避免死锁 务必要解锁将其添加在finally中
                        lock.unlock();
                    }
                } else {
                    // 未得到锁
                    try {
                        // 等待其他拿到锁的操作将数据保存到缓存中
                        TimeUnit.SECONDS.sleep(5);
                        // 再次从缓存中获取
                        spuSaleAttrListCheckBySku = (List<SpuSaleAttr>) redisTemplate.opsForValue().get(redisKey);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return spuSaleAttrListCheckBySku;
    }

    /**
     * 根据spuId 查询不同销售属性值组合和库存id
     *
     * @param spuId
     * @return
     */
    @Override
    @GmallCache(prefix = RedisConst.SKUVALUEIDS_PREFIX)
    public Map getSkuValueIdsMap(Long spuId) {
        Map map = new HashMap();
        // 数据库返回多条数据使用List接收
        List<Map> mapList = skuSaleAttrValueMapper.getSkuValueIdsMap(spuId);
        if (mapList != null) {
            mapList.forEach(map1 -> {
                map.put(map1.get("values_id"), map1.get("sku_id"));
            });
            return map;
        }
        return null;
    }

    /**
     * 首页数据展示
     *
     * @return
     */
    @Override
    public List<BaseCategoryView> getBaseCategoryViewList() {
        return baseCategoryViewMapper.selectList(null);
    }

    // 获取品牌相关信息
    @Override
    public BaseTrademark getBaseTrademark(Long tmId) {
        return baseTrademarkMapper.selectById(tmId);
    }

    // 获取库存的平台属性
    @Override
    public List<SkuAttrValue> getSkuAttrValue(Long skuId) {
        return skuAttrValueMapper.getSkuAttrValue(skuId);

    }
    /*@Override
    public Map getSkuValueIdsMap(Long spuId) {
        Map map = new HashMap();
        String redisKey = RedisConst.SKUVALUEIDS_PREFIX + spuId + RedisConst.SKUVALUEIDS_SUFFIX;
        // 从缓存中查询
        List<Map> mapList = (List<Map>)redisTemplate.opsForValue().get(redisKey);
        // 如果缓存中不存在
        if (mapList == null) {
            // 则从数据库中查询
            // 如果DB中该数据为热点数据 则可能会引起缓存击穿问题
            // 1.为解决缓存击穿问题使用分布式锁
            // 1.1设置分布式锁的key
            String cacheClock = RedisConst.SKUVALUEIDS_PREFIX + spuId + RedisConst.SKULOCK_SUFFIX;
            // 1.2设置分布式锁名 解决 分布式锁问题之误删操作
            String uuid = UUID.randomUUID().toString();
            // 1.3设置过期时间 解决 分布式问题之死锁操作
            Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(cacheClock, uuid, 3, TimeUnit.SECONDS);
            if (ifAbsent) {
                try {
                    // 数据库返回多条数据使用List接收
                    // 从数据库中查询
                    mapList = skuSaleAttrValueMapper.getSkuValueIdsMap(spuId);
                    if (mapList != null) {
                        Map finalMap = map;
                        mapList.forEach(map1 -> {
                            finalMap.put(map1.get("values_id"), map1.get("sku_id"));
                        });
                        map = finalMap;
                        // 保存到缓存中
                        // 避免缓存雪崩设置不同的过期时间
                        redisTemplate.opsForValue().set(redisKey, map, RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(500), TimeUnit.SECONDS);
                    } else {
                        map = new HashMap();
                        // 避免缓存击穿 将null值存入缓存中
                        redisTemplate.opsForValue().set(redisKey, map, 5, TimeUnit.MINUTES);
                    }
                } finally {
                    // 避免死锁 务必要解锁将其添加在finally中 使用LUA脚本
                    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
                    this.redisTemplate.execute(new DefaultRedisScript<>(script), Collections.singletonList(cacheClock), uuid);
                }
            } else {
                // 未获取到锁
                try {
                    TimeUnit.SECONDS.sleep(5);
                    mapList = (List<Map>) redisTemplate.opsForValue().get(redisKey);
                    if (mapList != null) {
                        Map finalMap = map;
                        mapList.forEach(map1 -> {
                            finalMap.put(map1.get("values_id"), map1.get("sku_id"));
                        });
                        map = finalMap;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }*/
}